package com.topisv.tms.rest.qimen.qmsend;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Date;
import java.util.Map;

import javax.xml.bind.JAXB;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.topisv.tms.entity.Customers;
import com.topisv.tms.entity.qimen.QmResendInfo;
import com.topisv.tms.exception.ErrorCode;
import com.topisv.tms.exception.PaiUException;
import com.topisv.tms.rest.qimen.qmentity.response.QMReponse;
import com.topisv.tms.rest.qimen.qmservice.QmResendInfoService;
import com.topisv.tms.rest.qimen.request.RequestParams;
import com.topisv.tms.service.CustomersService;
import com.topisv.tms.utils.InitProperties;
import com.topisv.tms.utils.TimeUtil;
import com.topisv.tms.utils.TopUtils;

@Component
@Lazy(false)
@Transactional(readOnly =  false)
public abstract class QmRequestSender<P> {
	protected Logger logger = LoggerFactory.getLogger(getClass());
	
	@Autowired
	private QmResendInfoService qmResendInfoService; 
	@Autowired
	private CustomersService customersService;	
//	protected RequestParams getSendParams(){
//		return this.sendParams;
//	}
//	
//	public void setAutoSend(boolean autoSend) {
//		this.autoSend = autoSend;
//	}
//	public P getSubParam(){
//		return this.subParam;
//	}

	public static String getSendUrl(RequestParams sendParams) throws Exception{
		//加密完成获取url
		Map<String,String> paramMap = sendParams.getParams();
		String timestamp = TimeUtil.getNowDateString(new Date(),"yyyy-MM-dd HH:mm:ss");
		paramMap.put("timestamp", timestamp);
		String qmUrl = InitProperties.get("qm.url");
		StringBuffer sb = new StringBuffer(qmUrl);
		sb.append("?");
		sb.append("method=").append(paramMap.get("method")+"&");
		sb.append("format=").append(paramMap.get("format")+"&");
		sb.append("app_key=").append(paramMap.get("app_key")+"&");
		sb.append("timestamp=").append(timestamp+"&");
		sb.append("v=").append(paramMap.get("v")+"&");
		sb.append("sign_method=").append(paramMap.get("sign_method")+"&");
		sb.append("customerId=").append(paramMap.get("customerId")+"&");
		//计算sign并设置sign
		setSign(sendParams);
		//将sign也放到url中
		sb.append("sign=").append(sendParams.getSign());
				
		String sendUrl = sb.toString().replace(" ", "%20");
		
		return sendUrl;
	}
	
	public String send(P params,String customerCode) throws Exception{
		//send请求
		String result = null;
		try{
			Customers customers = customersService.findByCustomerCode(customerCode);
			if(customers == null||customers.getOpenQm() == null||"0".equals(customers.getOpenQm())){
				//logger.info("商户：{} 未接入奇门不需要发送",customerCode);
				return "未接入奇门不需要发送";
			}
			RequestParams sendParams=new RequestParams();
			P subParam=params;
			
			//设置参数
			sendParams = setupParam(sendParams);
			if(sendParams==null){
				throw new Exception("no params");
			}
			//设置app_key
			String qmAppKey = InitProperties.get("regAppKey");
			sendParams.getParams().put("app_key", qmAppKey);
			
			
			//执行具体实现
			String sendXml = execute(subParam,sendParams);
			sendParams.setRequestXml(sendXml);
			if(StringUtils.isEmpty(sendXml)){
				return sendXml;
			}
			logger.info("url:{} sendXml:{}",getSendUrl(sendParams),sendXml);
			
			try{
				 String responseXml = pub2(getSendUrl(sendParams), sendXml);
				 logger.info("响应报文：{}",responseXml);
				 QMReponse qmp = null;
				 try{
					 qmp = JAXB.unmarshal(new StringReader(responseXml), QMReponse.class);
				 }catch(Exception e){
					 logger.error("响应报文解析异常",e);
				 }
				 if(qmp!=null&&"success".equals(qmp.getFlag())){
					 result = "success";
				 }else {
					 result = "failure";
					 QmResendInfo qmResendInfo = new QmResendInfo(sendXml); 
					//加密完成获取url
					 Map<String,String> paramMap = sendParams.getParams();
					 qmResendInfo.setMethod(paramMap.get("method"));
					 qmResendInfo.setFormat(paramMap.get("format"));
					 qmResendInfo.setAppKey(paramMap.get("app_key"));
					 qmResendInfo.setV(paramMap.get("v"));
					 qmResendInfo.setSignMethod(paramMap.get("sign_method"));
					 qmResendInfo.setCustomerId(paramMap.get("customerId"));
					 qmResendInfo.setSecret(sendParams.getSecret());
					 qmResendInfoService.save(qmResendInfo);
				 }
//				 logger.info("奇门回传结果  Flag:{}({}) Code:{} Message:{} xml:{}",result,qmp.getFlag(),qmp.getCode(),qmp.getMessage(),responseXml);
			}catch(Exception e){
				result = "failure";
				logger.info("error:{}",e);
			}
		}catch(Exception e){
			logger.error("奇门发送失败,数据获取异常",e);
		}
		return result;
	}
	
	protected abstract RequestParams setupParam(RequestParams sendParams);
	
	protected abstract String execute(P params,RequestParams sendParams);
	
	protected static void setSign(RequestParams sendParams) throws Exception{
		String sign = TopUtils.signQMRequest(sendParams);
		sendParams.setSign(sign);
	}
	
	
	
	
	
	public static String pub2(String serviceURL, String param) throws PaiUException{
		URL url = null;
		HttpURLConnection connection = null;
		StringBuffer buffer = new StringBuffer();
		try {
			url = new URL(serviceURL);
			connection = (HttpURLConnection) url.openConnection();
			connection.setDoOutput(true);
			connection.setDoInput(true);
			connection.setUseCaches(false);
			connection.setRequestMethod("POST");
			connection.setRequestProperty("Content-Length",param.length()+"");
			connection.setRequestProperty("Content-Type", "text/xml");
			// connection.setRequestProperty("User-Agent","Java/1.6.0_29");
			//connection.connect();
//			String username = "Annto_PaiU";
//	    	String password = "nDsht3^v";
//	    	String input = username + ":" + password; 
//	    	String encoding = getBASE64(input);   
//	    	connection.setRequestProperty( "Authorization","Basic "+encoding); 
			/*OutputStream os=connection.getOutputStream();
	        DataOutputStream dos=new DataOutputStream(os);
	        dos.write(param.getBytes("UTF-8"));
	        dos.flush();
	        dos.close(); */
			OutputStream outputStream = connection.getOutputStream();
			outputStream.write(param.getBytes("UTF-8"));
			outputStream.flush();
			outputStream.close();
			InputStream inputStream = connection.getInputStream();
			byte[] bytes = new byte[1024];
			int count = inputStream.read(bytes);
			while (count != -1) {
				buffer.append(new String(bytes, 0, count, "UTF-8"));
				count = inputStream.read(bytes);
			}
			inputStream.close();
		} catch (IOException e) {
			throw new PaiUException(ErrorCode.DATA_ERROR);
		} finally {
			if (connection != null) {
				connection.disconnect();
			}
		}
		return buffer.toString();
	}
	
//	public static String getBASE64(String str) throws PaiUException{
//		   String s = null;
//		   if (str != null) {
//		    try {
//				s = new sun.misc.BASE64Encoder().encode(str.getBytes("UTF-8"));
//			} catch (UnsupportedEncodingException e) {
//				throw new PaiUException(ErrorCode.DATA_ERROR);
//			}
//		  }
//		  return s;
//		}
	
}
